#include<iostream>
#include<cstdlib>
using namespace std;

#define max 100

struct{
    int mat; //matricula
    float n1; //nota 1
    float n2; //nota 2
    float media;
    float faltas;
}typedef Aluno;

struct{
    int next;
    Aluno alunos[max];
}typedef Lista;

Lista* lista;

void menu();
int getEnd(const Lista *list);
bool isEmpty(const Lista *list);
bool isFull(const Lista *list);
bool create(Lista *list);
bool erase(Lista *list);
bool insere(Aluno *aluno, Lista *list, int p);
bool insertOrdered(Aluno *aluno, Lista *list);
int verifica(Aluno *aluno, Lista *list);
void mostra(const Lista *l);



int main(int argc, char** argv){
    lista = new Lista;
    create(lista);
    Aluno* a = new Aluno;
    int isThere = -1;
    int pos = -1;
    int choice = -1;
    while(choice != 5) {
        menu();
        cout << endl << endl << "Your choice is: ";
        cin >> choice;
        switch(choice){
        case 1:
            mostra(lista);
            cin.get();
            break;
        case 2:
            cout << endl <<"Enter with the enrollment number: ";
            cin >> a->mat;
            cout << endl << "Enter with the 1st score: ";
            cin >> a->n1;
            cout << endl <<"Enter with the 2nd score: ";
            cin >> a->n2;
            a->media = (float) (a->n1 + a->n2)/2;
            cout << endl<<"Enter with the absence: ";
            cin >> a->faltas;
            if(lista->next != 0 )
            {
                cout << endl << "Enter with the position to insert or -1 do insert ordered: ";
                cin >> pos;
            }
            if(lista->next == 0){
                if(!insere(a, lista, 0))cout << endl<< "It's not possible to insert" << endl;
                else cout << endl << "Success to insert!";
            }
            else {
                    if (pos == -1) {
                        if(!insertOrdered(a, lista)) cout << endl<< "It's not possible to insert" << endl;
                        else cout << endl << "Success to insert!";
                    }
                    else {
                            if(!insere(a, lista, pos))cout << endl<< "It's not possible to insert" << endl;
                            else cout << endl << "Success to insert!";
                    }
            }
            break;
        case 3:
            cout << endl <<"Enter with the enrollment number: ";
            cin >> a->mat;
            cout << endl << "Enter with the 1st score: ";
            cin >> a->n1;
            cout << endl <<"Enter with the 2nd score: ";
            cin >> a->n2;
            a->media = (float) (a->n1 + a->n2)/2;
            cout << endl<<"Enter with the absence: ";
            cin >> a->faltas;
            isThere = verifica(a, lista);
            if(isThere == -1) cout << endl << "Student is not present on the list!";
            else cout << endl << "Student is in position "<< isThere;
            break;

        case 4:
            if(erase(lista)) cout << endl << "List erased with success!";
            else cout << endl << "Problems for erase the list";
            if(lista) free(lista);
            break;

        case 5: if(lista) free(lista); break;

        default: system("cls");
        }

    }



    return 0;
}


void menu(){
    if(lista->next == 0){
            cout << endl << "Welcome to DOS Academic Portal!!!";
            cout << endl << "Press (2) to Insert";
    }
    else{
        cout << endl << "What do you want to do?" << endl;
        cout << endl << "1 - Show";
        cout << endl << "2 - Insert";
        cout << endl << "3 - Verify";
        cout << endl << "4 - Erase list";
        cout << endl << "5 - Shutdown";
    }

}

//This function returns the end of list
int getEnd(const Lista *list){
    return (list->next);
}

//This function returns if the list is empty
bool isEmpty(const Lista *list){
    return (list->next == 0); //if list->next == 0 returns true, else returns false
}

//This function returns if the list is full
bool isFull(const Lista *list){
    return (list->next >= max);
}

//This function creates a list
bool create(Lista *list){
    list->next = 0;
}

//This function erases the list
bool erase(Lista *list){
    list->next = 0;
}

//This function insert an element into a position on the list
bool insere(Aluno *a, Lista *list, int p){
    if(p > getEnd(list) || p < 0) return false;
    if(isFull(list)) return false;
    if(list->next == 0){
        list->alunos[0] = *a;
        list->next++;
        return true;
    }
    else{
        int i;
        for(i=list->next; i > p; i--){
            list->alunos[i] = list->alunos[i-1];
        }
        list->alunos[i] = *a;
        list->next++;
        return true;
    }
    return false;
}

//This function inserts ordered
bool insertOrdered(Aluno *a, Lista *list){
    int i = 0; //position
    while((i < list->next) && (a->mat < list->alunos[i].mat)) i++;
    return insere(a, list, i);
}

int verifica(Aluno *a, Lista *list){
    int inf,sup, meio;
    if(!isEmpty(list)){
        inf=0;
        sup = (list->next -1);
        while(inf <= sup){
            meio = (inf + sup)/2;
            if(list->alunos[meio].mat == a->mat) return meio;
            else if(list->alunos[meio].mat < a->mat) inf = (meio+1);
            else sup = (meio-1);
        }//end-while
    }//end-if
    return getEnd(list);
}

void mostra(const Lista *list){
    if(!isEmpty(list)){
        cout << endl << endl<< "Printing list if it's not empty..." << endl;
        cout << "Enrollment number - Score 1 - Score 2 - Average - Absence" << endl;
        for (int i=0; i < list->next; i++){
            cout << endl;
            cout << list->alunos[i].mat << " - ";
            cout << list->alunos[i].n1 << " - ";
            cout << list->alunos[i].n2 << " - ";
            cout << list->alunos[i].media << " - ";
            cout << list->alunos[i].faltas << " - ";
        }
    }
}
